Datos

Los datos provistos por esta aplicación constituyen estadísticas operacionales de la Policía de Puerto Rico. Su finalidad es única y exclusivamente como medio informativo y pueden no reflejar los porcentajes actuales. https://data.pr.gov/en/Seguridad-P-blica/Incidencia-Crime-Map/3fy3-2bc5. Una copia parcial está disponible en el folder datos/.

library(tidyverse)
library(lubridate)
library(leaflet)
library(readr)
crimen_pr <- read_csv("Datos/crimen_pr.csv")

── Column specification ────────────────────────────────────────────────────────────────────────────────────
cols(
  Fecha = col_date(format = ""),
  Hora = col_time(format = ""),
  Delito = col_double(),
  Delitos_code = col_character(),
  POINT_X = col_double(),
  POINT_Y = col_double(),
  `Area Policiaca` = col_character()
)
crimen = crimen_pr
head(crimen)


library(readr)
Incidencia_Crime_Map_2019 <- read_csv("Incidencia_Crime_Map_2019.csv")

── Column specification ────────────────────────────────────────────────────────────────────────────────────
cols(
  Fecha = col_character(),
  Hora = col_time(format = ""),
  Delito = col_double(),
  Delitos_code = col_character(),
  POINT_X = col_double(),
  POINT_Y = col_double(),
  Location = col_character(),
  `Area Policiaca` = col_character()
)
crimen_2019 = Incidencia_Crime_Map_2019
head(crimen_2019)

El paquete janitor se puede usar para limpiar los nombres de las columnas

library(janitor)

crm <- crimen_2019 %>%
  clean_names() %>%
  rename(longitud = point_y, latitud = point_x)

crm

Use una gráfica para verificar si hay coordenadas afuera del perímetro de la isla

crm %>%
  ggplot() +
  geom_point(aes(longitud, latitud))

Con el comando filter() remueva las coordenadas que son inválidas

crm <- crimen %>%
  clean_names() %>%
  filter(!is.na(point_x), point_x != 0) %>%
  rename(longitud = point_y, latitud = point_x)

Chequee otra vez que las coordenads están dentro de los limites

crm %>%
  ggplot() +
  geom_point(aes(longitud, latitud))

La función map_data(), del paquete ggplot2, contiene el mapa mundial. El mapa de Puerto Rico se puede acceder usando el argumento region.

crm %>%
  filter(area_policiaca=="Arecibo") %>% 
  ggplot() +
  geom_point(aes(longitud, latitud))

pr <- map_data("world", region = "Puerto Rico")

Use geom_map() para agregar la figura del territorio

ggplot() +
  geom_map(aes(long, lat, map_id = region), fill = "gray",  map = pr, data = pr) 
Ignoring unknown aesthetics: x, y

Mapa de otro pais…

vea tambien https://www.r-spatial.org/r/2018/10/25/ggplot2-sf.html

fr <- map_data("world", region = "France")
fr
ggplot() +
  geom_map(aes(long, lat, map_id = region), fill = "gray",  map = fr, data = fr) 
Ignoring unknown aesthetics: x, y

world_map <- map_data("world")
ggplot(world_map, aes(x = long, y = lat, group = group)) +
  geom_polygon(fill="lightgray", colour = "white")

List of countries in the database of map_data

sort(unique(map_data("world")$region))
  [1] "Afghanistan"                         "Albania"                            
  [3] "Algeria"                             "American Samoa"                     
  [5] "Andorra"                             "Angola"                             
  [7] "Anguilla"                            "Antarctica"                         
  [9] "Antigua"                             "Argentina"                          
 [11] "Armenia"                             "Aruba"                              
 [13] "Ascension Island"                    "Australia"                          
 [15] "Austria"                             "Azerbaijan"                         
 [17] "Azores"                              "Bahamas"                            
 [19] "Bahrain"                             "Bangladesh"                         
 [21] "Barbados"                            "Barbuda"                            
 [23] "Belarus"                             "Belgium"                            
 [25] "Belize"                              "Benin"                              
 [27] "Bermuda"                             "Bhutan"                             
 [29] "Bolivia"                             "Bonaire"                            
 [31] "Bosnia and Herzegovina"              "Botswana"                           
 [33] "Brazil"                              "Brunei"                             
 [35] "Bulgaria"                            "Burkina Faso"                       
 [37] "Burundi"                             "Cambodia"                           
 [39] "Cameroon"                            "Canada"                             
 [41] "Canary Islands"                      "Cape Verde"                         
 [43] "Cayman Islands"                      "Central African Republic"           
 [45] "Chad"                                "Chagos Archipelago"                 
 [47] "Chile"                               "China"                              
 [49] "Christmas Island"                    "Cocos Islands"                      
 [51] "Colombia"                            "Comoros"                            
 [53] "Cook Islands"                        "Costa Rica"                         
 [55] "Croatia"                             "Cuba"                               
 [57] "Curacao"                             "Cyprus"                             
 [59] "Czech Republic"                      "Democratic Republic of the Congo"   
 [61] "Denmark"                             "Djibouti"                           
 [63] "Dominica"                            "Dominican Republic"                 
 [65] "Ecuador"                             "Egypt"                              
 [67] "El Salvador"                         "Equatorial Guinea"                  
 [69] "Eritrea"                             "Estonia"                            
 [71] "Ethiopia"                            "Falkland Islands"                   
 [73] "Faroe Islands"                       "Fiji"                               
 [75] "Finland"                             "France"                             
 [77] "French Guiana"                       "French Polynesia"                   
 [79] "French Southern and Antarctic Lands" "Gabon"                              
 [81] "Gambia"                              "Georgia"                            
 [83] "Germany"                             "Ghana"                              
 [85] "Greece"                              "Greenland"                          
 [87] "Grenada"                             "Grenadines"                         
 [89] "Guadeloupe"                          "Guam"                               
 [91] "Guatemala"                           "Guernsey"                           
 [93] "Guinea"                              "Guinea-Bissau"                      
 [95] "Guyana"                              "Haiti"                              
 [97] "Heard Island"                        "Honduras"                           
 [99] "Hungary"                             "Iceland"                            
[101] "India"                               "Indonesia"                          
[103] "Iran"                                "Iraq"                               
[105] "Ireland"                             "Isle of Man"                        
[107] "Israel"                              "Italy"                              
[109] "Ivory Coast"                         "Jamaica"                            
[111] "Japan"                               "Jersey"                             
[113] "Jordan"                              "Kazakhstan"                         
[115] "Kenya"                               "Kiribati"                           
[117] "Kosovo"                              "Kuwait"                             
[119] "Kyrgyzstan"                          "Laos"                               
[121] "Latvia"                              "Lebanon"                            
[123] "Lesotho"                             "Liberia"                            
[125] "Libya"                               "Liechtenstein"                      
[127] "Lithuania"                           "Luxembourg"                         
[129] "Macedonia"                           "Madagascar"                         
[131] "Madeira Islands"                     "Malawi"                             
[133] "Malaysia"                            "Maldives"                           
[135] "Mali"                                "Malta"                              
[137] "Marshall Islands"                    "Martinique"                         
[139] "Mauritania"                          "Mauritius"                          
[141] "Mayotte"                             "Mexico"                             
[143] "Micronesia"                          "Moldova"                            
[145] "Monaco"                              "Mongolia"                           
[147] "Montenegro"                          "Montserrat"                         
[149] "Morocco"                             "Mozambique"                         
[151] "Myanmar"                             "Namibia"                            
[153] "Nauru"                               "Nepal"                              
[155] "Netherlands"                         "Nevis"                              
[157] "New Caledonia"                       "New Zealand"                        
[159] "Nicaragua"                           "Niger"                              
[161] "Nigeria"                             "Niue"                               
[163] "Norfolk Island"                      "North Korea"                        
[165] "Northern Mariana Islands"            "Norway"                             
[167] "Oman"                                "Pakistan"                           
[169] "Palau"                               "Palestine"                          
[171] "Panama"                              "Papua New Guinea"                   
[173] "Paraguay"                            "Peru"                               
[175] "Philippines"                         "Pitcairn Islands"                   
[177] "Poland"                              "Portugal"                           
[179] "Puerto Rico"                         "Qatar"                              
[181] "Republic of Congo"                   "Reunion"                            
[183] "Romania"                             "Russia"                             
[185] "Rwanda"                              "Saba"                               
[187] "Saint Barthelemy"                    "Saint Helena"                       
[189] "Saint Kitts"                         "Saint Lucia"                        
[191] "Saint Martin"                        "Saint Pierre and Miquelon"          
[193] "Saint Vincent"                       "Samoa"                              
[195] "San Marino"                          "Sao Tome and Principe"              
[197] "Saudi Arabia"                        "Senegal"                            
[199] "Serbia"                              "Seychelles"                         
[201] "Siachen Glacier"                     "Sierra Leone"                       
[203] "Singapore"                           "Sint Eustatius"                     
[205] "Sint Maarten"                        "Slovakia"                           
[207] "Slovenia"                            "Solomon Islands"                    
[209] "Somalia"                             "South Africa"                       
[211] "South Georgia"                       "South Korea"                        
[213] "South Sandwich Islands"              "South Sudan"                        
[215] "Spain"                               "Sri Lanka"                          
[217] "Sudan"                               "Suriname"                           
[219] "Swaziland"                           "Sweden"                             
[221] "Switzerland"                         "Syria"                              
[223] "Taiwan"                              "Tajikistan"                         
[225] "Tanzania"                            "Thailand"                           
[227] "Timor-Leste"                         "Tobago"                             
[229] "Togo"                                "Tonga"                              
[231] "Trinidad"                            "Tunisia"                            
[233] "Turkey"                              "Turkmenistan"                       
[235] "Turks and Caicos Islands"            "Uganda"                             
[237] "UK"                                  "Ukraine"                            
[239] "United Arab Emirates"                "Uruguay"                            
[241] "USA"                                 "Uzbekistan"                         
[243] "Vanuatu"                             "Vatican"                            
[245] "Venezuela"                           "Vietnam"                            
[247] "Virgin Islands"                      "Wallis and Futuna"                  
[249] "Western Sahara"                      "Yemen"                              
[251] "Zambia"                              "Zimbabwe"                           

Agrege la capa con los datos de crimen

ggplot() +
  geom_map(aes(long, lat, map_id = region), fill = "grey",  map = pr, data = pr) + 
  geom_point(aes(longitud, latitud), data = crm)
Ignoring unknown aesthetics: x, y

theme_void() remueve la información alrededor del mapa

ggplot() +
  geom_map(aes(long, lat, map_id = region), fill = "gray",  map = pr, data = pr) +
  geom_point(aes(longitud, latitud), color = "blue", size = 0.1, data = crm) +
  theme_void() 
Ignoring unknown aesthetics: x, y

Los colores de los puntos se pueden

ggplot() +
  geom_map(aes(long, lat, map_id = region), fill = "gray",  map = pr, data = pr) +
  geom_point(aes(longitud, latitud, color = area_policiaca), size = 0.5, data = crm) +
  theme_void() +
  theme(legend.position = "bottom")
Ignoring unknown aesthetics: x, y

facet_wrap() permite crear una “mini” gráfica por cada segmento de los datos. En este caso, area_policiaca

ggplot() +
  geom_map(aes(long, lat, map_id = region), fill = "gray",  map = pr, data = pr) +
  geom_point(aes(longitud, latitud, color = area_policiaca), size = 0.2, data = crm) +
  theme_void() +
  facet_wrap(~delitos_code)
Ignoring unknown aesthetics: x, y

Ajustes se pueden hacer a los colores para obtener una mejor vista de la información.

ggplot() +
  geom_map(aes(long, lat, map_id = region), fill = "black",  map = pr, data = pr) +
  geom_point(aes(longitud, latitud), alpha = 0.2, size = 0.1, color = "#ffff00", data = crm) +
  theme_void() +
  theme(panel.background = element_rect(fill = "#333333")) +
  facet_wrap(~delitos_code)
Ignoring unknown aesthetics: x, y

leaflet

Leaflet (https://leafletjs.com/) es una librería de JavaScript que se utiliza para hacer mapas interactivos. Es la más usada hoy en día. El paquete de R llamado leaflet permite la integración con esta librería.

En lugar de usar +, leaflet utiliza el pipe (%>%) para crear las visualizaciones. Se necesita addTiles() para agregar el mapa, y después algún tipo de puntos geográficos.

library(leaflet)

crm %>%
  filter(month(fecha) == 8) %>%
  leaflet() %>%
  addTiles() %>%
  addMarkers(~longitud, ~latitud)

Ya que son interactivos, se pueden agregar nombres que salen cuando se hace un click al punto

crm %>%
  filter(month(fecha) == 8) %>%
  leaflet() %>%
  addTiles() %>%
  addMarkers(~longitud, ~latitud, popup = ~delitos_code)
crm %>%
  filter(month(fecha) == 8) %>%
  leaflet() %>%
  addTiles() %>%
  addMarkers(~longitud, ~latitud, popup = ~paste0("Delito: ",delitos_code))

markerClusterOptions() agrupa los puntos automaticamente para que la interactividad sea más fácil

crm %>%
  leaflet() %>%
  addTiles() %>%
  addMarkers(~longitud, ~latitud,  popup = ~paste0("Delito: ",delitos_code), clusterOptions = markerClusterOptions())
crm %>%
  filter(delitos_code == "Vehiculo Hurtado") %>%
  leaflet() %>%
  addTiles() %>%
  addMarkers(~longitud, ~latitud,  popup = ~paste0("Delito: ",delitos_code), clusterOptions = markerClusterOptions())

awesomeIcons

See these websites for markers and icons

http://rstudio.github.io/leaflet/markers.html

https://fontawesome.com/v4.7.0/icons/

LS0tCnRpdGxlOiAiTWFwYXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlID0gRkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShsZWFmbGV0KQpsaWJyYXJ5KGphbml0b3IpCmBgYAoKIyBEYXRvcwoKTG9zIGRhdG9zIHByb3Zpc3RvcyBwb3IgZXN0YSBhcGxpY2FjacOzbiBjb25zdGl0dXllbiBlc3RhZMOtc3RpY2FzIG9wZXJhY2lvbmFsZXMgZGUgbGEgUG9saWPDrWEgZGUgUHVlcnRvIFJpY28uIFN1IGZpbmFsaWRhZCBlcyDDum5pY2EgeSBleGNsdXNpdmFtZW50ZSBjb21vIG1lZGlvIGluZm9ybWF0aXZvIHkgcHVlZGVuIG5vIHJlZmxlamFyIGxvcyBwb3JjZW50YWplcyBhY3R1YWxlcy4gaHR0cHM6Ly9kYXRhLnByLmdvdi9lbi9TZWd1cmlkYWQtUC1ibGljYS9JbmNpZGVuY2lhLUNyaW1lLU1hcC8zZnkzLTJiYzUuIFVuYSBjb3BpYSBwYXJjaWFsIGVzdMOhIGRpc3BvbmlibGUgZW4gZWwgZm9sZGVyIGBkYXRvcy9gLgoKCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KGxlYWZsZXQpCmBgYAoKYGBge3J9CmxpYnJhcnkocmVhZHIpCmNyaW1lbl9wciA8LSByZWFkX2NzdigiRGF0b3MvY3JpbWVuX3ByLmNzdiIpCmNyaW1lbiA9IGNyaW1lbl9wcgpoZWFkKGNyaW1lbikKCgpsaWJyYXJ5KHJlYWRyKQpJbmNpZGVuY2lhX0NyaW1lX01hcF8yMDE5IDwtIHJlYWRfY3N2KCJJbmNpZGVuY2lhX0NyaW1lX01hcF8yMDE5LmNzdiIpCmNyaW1lbl8yMDE5ID0gSW5jaWRlbmNpYV9DcmltZV9NYXBfMjAxOQpoZWFkKGNyaW1lbl8yMDE5KQpgYGAKCkVsIHBhcXVldGUgYGphbml0b3JgIHNlIHB1ZWRlIHVzYXIgcGFyYSBsaW1waWFyIGxvcyBub21icmVzIGRlIGxhcyBjb2x1bW5hcwoKYGBge3J9CmxpYnJhcnkoamFuaXRvcikKCmNybSA8LSBjcmltZW5fMjAxOSAlPiUKICBjbGVhbl9uYW1lcygpICU+JQogIHJlbmFtZShsb25naXR1ZCA9IHBvaW50X3ksIGxhdGl0dWQgPSBwb2ludF94KQoKY3JtCmBgYAoKVXNlIHVuYSBncsOhZmljYSBwYXJhIHZlcmlmaWNhciBzaSBoYXkgY29vcmRlbmFkYXMgYWZ1ZXJhIGRlbCBwZXLDrW1ldHJvIGRlIGxhIGlzbGEKCmBgYHtyfQpjcm0gJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoYWVzKGxvbmdpdHVkLCBsYXRpdHVkKSkKYGBgCgpDb24gZWwgY29tYW5kbyBgZmlsdGVyKClgIHJlbXVldmEgbGFzIGNvb3JkZW5hZGFzIHF1ZSBzb24gaW52w6FsaWRhcwoKYGBge3J9CmNybSA8LSBjcmltZW4gJT4lCiAgY2xlYW5fbmFtZXMoKSAlPiUKICBmaWx0ZXIoIWlzLm5hKHBvaW50X3gpLCBwb2ludF94ICE9IDApICU+JQogIHJlbmFtZShsb25naXR1ZCA9IHBvaW50X3ksIGxhdGl0dWQgPSBwb2ludF94KQpgYGAKCkNoZXF1ZWUgb3RyYSB2ZXogcXVlIGxhcyBjb29yZGVuYWRzIGVzdMOhbiBkZW50cm8gZGUgbG9zIGxpbWl0ZXMKCmBgYHtyLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDN9CmNybSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChhZXMobG9uZ2l0dWQsIGxhdGl0dWQpKQpgYGAKCkxhIGZ1bmNpw7NuIGBtYXBfZGF0YSgpYCwgZGVsIHBhcXVldGUgYGdncGxvdDJgLCBjb250aWVuZSBlbCBtYXBhIG11bmRpYWwuICBFbCBtYXBhIGRlIFB1ZXJ0byBSaWNvIHNlIHB1ZWRlIGFjY2VkZXIgdXNhbmRvIGVsIGFyZ3VtZW50byBgcmVnaW9uYC4KCgpgYGB7ciwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSAzfQpjcm0gJT4lCiAgZmlsdGVyKGFyZWFfcG9saWNpYWNhPT0iQXJlY2libyIpICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChhZXMobG9uZ2l0dWQsIGxhdGl0dWQpKQpgYGAKCgpgYGB7cn0KcHIgPC0gbWFwX2RhdGEoIndvcmxkIiwgcmVnaW9uID0gIlB1ZXJ0byBSaWNvIikKYGBgCgpVc2UgYGdlb21fbWFwKClgIHBhcmEgYWdyZWdhciBsYSBmaWd1cmEgZGVsIHRlcnJpdG9yaW8KCmBgYHtyLCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDN9CmdncGxvdCgpICsKICBnZW9tX21hcChhZXMobG9uZywgbGF0LCBtYXBfaWQgPSByZWdpb24pLCBmaWxsID0gImdyYXkiLCAgbWFwID0gcHIsIGRhdGEgPSBwcikgCmBgYAoKIyBNYXBhIGRlIG90cm8gcGFpcy4uLgoKdmVhIHRhbWJpZW4gaHR0cHM6Ly93d3cuci1zcGF0aWFsLm9yZy9yLzIwMTgvMTAvMjUvZ2dwbG90Mi1zZi5odG1sCgoKYGBge3J9CmZyIDwtIG1hcF9kYXRhKCJ3b3JsZCIsIHJlZ2lvbiA9ICJGcmFuY2UiKQpmcgpgYGAKCmBgYHtyfQpnZ3Bsb3QoKSArCiAgZ2VvbV9tYXAoYWVzKGxvbmcsIGxhdCwgbWFwX2lkID0gcmVnaW9uKSwgZmlsbCA9ICJncmF5IiwgIG1hcCA9IGZyLCBkYXRhID0gZnIpIApgYGAKYGBge3J9CndvcmxkX21hcCA8LSBtYXBfZGF0YSgid29ybGQiKQpnZ3Bsb3Qod29ybGRfbWFwLCBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXApKSArCiAgZ2VvbV9wb2x5Z29uKGZpbGw9ImxpZ2h0Z3JheSIsIGNvbG91ciA9ICJ3aGl0ZSIpCmBgYAoKIyBMaXN0IG9mIGNvdW50cmllcyBpbiB0aGUgZGF0YWJhc2Ugb2YgbWFwX2RhdGEKCmBgYHtyfQpzb3J0KHVuaXF1ZShtYXBfZGF0YSgid29ybGQiKSRyZWdpb24pKQpgYGAKCgoKQWdyZWdlIGxhIGNhcGEgY29uIGxvcyBkYXRvcyBkZSBjcmltZW4gCgpgYGB7ciwgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSAzfQpnZ3Bsb3QoKSArCiAgZ2VvbV9tYXAoYWVzKGxvbmcsIGxhdCwgbWFwX2lkID0gcmVnaW9uKSwgZmlsbCA9ICJncmV5IiwgIG1hcCA9IHByLCBkYXRhID0gcHIpICsgCiAgZ2VvbV9wb2ludChhZXMobG9uZ2l0dWQsIGxhdGl0dWQpLCBkYXRhID0gY3JtKQpgYGAKCmB0aGVtZV92b2lkKClgIHJlbXVldmUgbGEgaW5mb3JtYWNpw7NuIGFscmVkZWRvciBkZWwgbWFwYQoKYGBge3IsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gM30KZ2dwbG90KCkgKwogIGdlb21fbWFwKGFlcyhsb25nLCBsYXQsIG1hcF9pZCA9IHJlZ2lvbiksIGZpbGwgPSAiZ3JheSIsICBtYXAgPSBwciwgZGF0YSA9IHByKSArCiAgZ2VvbV9wb2ludChhZXMobG9uZ2l0dWQsIGxhdGl0dWQpLCBjb2xvciA9ICJibHVlIiwgc2l6ZSA9IDAuMSwgZGF0YSA9IGNybSkgKwogIHRoZW1lX3ZvaWQoKSAKYGBgCgpMb3MgY29sb3JlcyBkZSBsb3MgcHVudG9zIHNlIHB1ZWRlbiAKCmBgYHtyLCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDMuNX0KZ2dwbG90KCkgKwogIGdlb21fbWFwKGFlcyhsb25nLCBsYXQsIG1hcF9pZCA9IHJlZ2lvbiksIGZpbGwgPSAiZ3JheSIsICBtYXAgPSBwciwgZGF0YSA9IHByKSArCiAgZ2VvbV9wb2ludChhZXMobG9uZ2l0dWQsIGxhdGl0dWQsIGNvbG9yID0gYXJlYV9wb2xpY2lhY2EpLCBzaXplID0gMC41LCBkYXRhID0gY3JtKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKYGBgCgpgZmFjZXRfd3JhcCgpYCBwZXJtaXRlIGNyZWFyIHVuYSAibWluaSIgZ3LDoWZpY2EgcG9yIGNhZGEgc2VnbWVudG8gZGUgbG9zIGRhdG9zLiAgRW4gZXN0ZSBjYXNvLCBgYXJlYV9wb2xpY2lhY2FgCgpgYGB7ciwgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSAzLjV9CmdncGxvdCgpICsKICBnZW9tX21hcChhZXMobG9uZywgbGF0LCBtYXBfaWQgPSByZWdpb24pLCBmaWxsID0gImdyYXkiLCAgbWFwID0gcHIsIGRhdGEgPSBwcikgKwogIGdlb21fcG9pbnQoYWVzKGxvbmdpdHVkLCBsYXRpdHVkLCBjb2xvciA9IGFyZWFfcG9saWNpYWNhKSwgc2l6ZSA9IDAuMiwgZGF0YSA9IGNybSkgKwogIHRoZW1lX3ZvaWQoKSArCiAgZmFjZXRfd3JhcCh+ZGVsaXRvc19jb2RlKQpgYGAKCkFqdXN0ZXMgc2UgcHVlZGVuIGhhY2VyIGEgbG9zIGNvbG9yZXMgcGFyYSBvYnRlbmVyIHVuYSBtZWpvciB2aXN0YSBkZSBsYSBpbmZvcm1hY2nDs24uCgpgYGB7ciwgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSAzLjV9CmdncGxvdCgpICsKICBnZW9tX21hcChhZXMobG9uZywgbGF0LCBtYXBfaWQgPSByZWdpb24pLCBmaWxsID0gImJsYWNrIiwgIG1hcCA9IHByLCBkYXRhID0gcHIpICsKICBnZW9tX3BvaW50KGFlcyhsb25naXR1ZCwgbGF0aXR1ZCksIGFscGhhID0gMC4yLCBzaXplID0gMC4xLCBjb2xvciA9ICIjZmZmZjAwIiwgZGF0YSA9IGNybSkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiMzMzMzMzMiKSkgKwogIGZhY2V0X3dyYXAofmRlbGl0b3NfY29kZSkKYGBgCgojIyBsZWFmbGV0CgpMZWFmbGV0IChodHRwczovL2xlYWZsZXRqcy5jb20vKSBlcyB1bmEgbGlicmVyw61hIGRlIEphdmFTY3JpcHQgcXVlIHNlIHV0aWxpemEgcGFyYSBoYWNlciBtYXBhcyBpbnRlcmFjdGl2b3MuICBFcyBsYSBtw6FzIHVzYWRhIGhveSBlbiBkw61hLiAgRWwgcGFxdWV0ZSBkZSBSIGxsYW1hZG8gYGxlYWZsZXRgIHBlcm1pdGUgbGEgaW50ZWdyYWNpw7NuIGNvbiBlc3RhIGxpYnJlcsOtYS4gIAoKRW4gbHVnYXIgZGUgdXNhciBgK2AsIGBsZWFmbGV0YCB1dGlsaXphIGVsIHBpcGUgKGAlPiVgKSBwYXJhIGNyZWFyIGxhcyB2aXN1YWxpemFjaW9uZXMuICBTZSBuZWNlc2l0YSBgYWRkVGlsZXMoKWAgcGFyYSBhZ3JlZ2FyIGVsIG1hcGEsIHkgZGVzcHXDqXMgYWxnw7puIHRpcG8gZGUgcHVudG9zIGdlb2dyw6FmaWNvcy4KCmBgYHtyfQpsaWJyYXJ5KGxlYWZsZXQpCgpjcm0gJT4lCiAgZmlsdGVyKG1vbnRoKGZlY2hhKSA9PSA4KSAlPiUKICBsZWFmbGV0KCkgJT4lCiAgYWRkVGlsZXMoKSAlPiUKICBhZGRNYXJrZXJzKH5sb25naXR1ZCwgfmxhdGl0dWQpCmBgYAoKWWEgcXVlIHNvbiBpbnRlcmFjdGl2b3MsIHNlIHB1ZWRlbiBhZ3JlZ2FyIG5vbWJyZXMgcXVlIHNhbGVuIGN1YW5kbyBzZSBoYWNlIHVuIGNsaWNrIGFsIHB1bnRvCgpgYGB7cn0KY3JtICU+JQogIGZpbHRlcihtb250aChmZWNoYSkgPT0gOCkgJT4lCiAgbGVhZmxldCgpICU+JQogIGFkZFRpbGVzKCkgJT4lCiAgYWRkTWFya2Vycyh+bG9uZ2l0dWQsIH5sYXRpdHVkLCBwb3B1cCA9IH5kZWxpdG9zX2NvZGUpCmBgYAoKCmBgYHtyfQpjcm0gJT4lCiAgZmlsdGVyKG1vbnRoKGZlY2hhKSA9PSA4KSAlPiUKICBsZWFmbGV0KCkgJT4lCiAgYWRkVGlsZXMoKSAlPiUKICBhZGRNYXJrZXJzKH5sb25naXR1ZCwgfmxhdGl0dWQsIHBvcHVwID0gfnBhc3RlMCgiRGVsaXRvOiAiLGRlbGl0b3NfY29kZSkpCmBgYAoKYG1hcmtlckNsdXN0ZXJPcHRpb25zKClgIGFncnVwYSBsb3MgcHVudG9zIGF1dG9tYXRpY2FtZW50ZSBwYXJhIHF1ZSBsYSBpbnRlcmFjdGl2aWRhZCBzZWEgbcOhcyBmw6FjaWwKCmBgYHtyfQpjcm0gJT4lCiAgbGVhZmxldCgpICU+JQogIGFkZFRpbGVzKCkgJT4lCiAgYWRkTWFya2Vycyh+bG9uZ2l0dWQsIH5sYXRpdHVkLCAgcG9wdXAgPSB+cGFzdGUwKCJEZWxpdG86ICIsZGVsaXRvc19jb2RlKSwgY2x1c3Rlck9wdGlvbnMgPSBtYXJrZXJDbHVzdGVyT3B0aW9ucygpKQpgYGAKCgpgYGB7cn0KY3JtICU+JQogIGZpbHRlcihkZWxpdG9zX2NvZGUgPT0gIlZlaGljdWxvIEh1cnRhZG8iKSAlPiUKICBsZWFmbGV0KCkgJT4lCiAgYWRkVGlsZXMoKSAlPiUKICBhZGRNYXJrZXJzKH5sb25naXR1ZCwgfmxhdGl0dWQsICBwb3B1cCA9IH5wYXN0ZTAoIkRlbGl0bzogIixkZWxpdG9zX2NvZGUpLCBjbHVzdGVyT3B0aW9ucyA9IG1hcmtlckNsdXN0ZXJPcHRpb25zKCkpCmBgYAoKIyBhd2Vzb21lSWNvbnMgCgojIyBTZWUgdGhlc2Ugd2Vic2l0ZXMgZm9yIG1hcmtlcnMgYW5kIGljb25zCgoKaHR0cDovL3JzdHVkaW8uZ2l0aHViLmlvL2xlYWZsZXQvbWFya2Vycy5odG1sCgpodHRwczovL2ZvbnRhd2Vzb21lLmNvbS92NC43LjAvaWNvbnMvCgoKYGBge3J9CmNybSAlPiUKICBmaWx0ZXIoZGVsaXRvc19jb2RlID09ICJWZWhpY3VsbyBIdXJ0YWRvIikgJT4lCiAgbGVhZmxldCgpICU+JQogIGFkZFRpbGVzKCkgJT4lCiAgYWRkQXdlc29tZU1hcmtlcnMofmxvbmdpdHVkLCB+bGF0aXR1ZCwgIHBvcHVwID0gfnBhc3RlMCgiRGVsaXRvOiAiLGRlbGl0b3NfY29kZSksIGNsdXN0ZXJPcHRpb25zID0gbWFya2VyQ2x1c3Rlck9wdGlvbnMoKSwgaWNvbiA9IGF3ZXNvbWVJY29ucyhpY29uID0gImZhLWZpcmUiLCBsaWJyYXJ5ID0gImZhIikpCgojZmEtY2FtZXJhLXJldHJvCiNmYS1maXJlCmBgYAoK